Test Failed
Branch master (272ac7)
by Sergii
01:57
created

DocGenerator.js ➔ ???   B

Complexity

Conditions 2
Paths 64

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 18
Bugs 0 Features 18
Metric Value
cc 2
c 18
b 0
f 18
nc 64
dl 0
loc 45
rs 8.8571
nop 3
1
const _             = require('lodash'),
2
      fs            = require('fs'),
3
      Handlebars    = require('handlebars'),
4
      HTML          = 'HTML',
5
      BaseGenerator = require('./BaseGenerator'),
6
      SwaggerParser = require('./SwaggerParser'),
7
      Markdown      = 'Markdown'
8
9
/**
10
 * @class DocGenerator
11
 * Documentation generator (html or MarkDown)
12
 *
13
 * @property {String} type Output documentation type
14
 * @property {String} version Swagger version
15
 * @property {String} destination Output destination
16
 * @property {String} templatePath Path to template
17
 * @property {ParserOptions} parserOptions Swagger parser options
18
 * @property {Function} generatorCallback Custom generator callback
19
 * @property {Object.<Object>} additionalLayouts Additional layouts for Handlebars in format <code><file-name-or-relative-path>: <template-name></code>
20
 * @property {Object.<Object>} additionalHelpers Additional helpers for Handlebars in format <code><helper-name>: function (Handlebars) {
21
 *  // Some helper detail
22
 * }</code>
23
 * @property {String} moduleName Module name
24
 * @property {String} className Class name
25
 * @property {String} destination Output doc destination
26
 * @property {String} docsPath Method definitions path
27
 * @property {String} modelPath Model path
28
 */
29
class DocGenerator extends BaseGenerator {
30
31
  /**
32
   * DocGenerator constructor
33
   *
34
   * @param {String} type Documentation type (html or Markdown). One of (Markdown or HTML)
35
   * @param {DocGeneratorOptionsObject} options Swagger documentation generator options
36
   * @param {String} version Swagger version (default is 2.0)
37
   */
38
  constructor (type, options, version) {
39
    super()
40
41
    version                = version || '2.0'
42
    options                = options || {}
43
    this.type              = type
44
    this.version           = version
45
    this.generatorCallback = options.generatorCallback
46
    this.templatePath      = (options.templatePath || (__dirname + '/' + this.version +
0 ignored issues
show
Compatibility introduced by
Consider using the path module for constructing paths since they are otherwise not cross-OS compatible.
Loading history...
47
      '/templates/' + this.type.toLowerCase() + '/')).replace(/\/\//g, '/')
48
    this.data              = options.swagger
49
    this.additionalLayouts = options.additionalLayouts || {}
50
    this.parserOptions     = options.parserOptions
51
    this.destination       = options.destination || __dirname + '/../dist'
0 ignored issues
show
Compatibility introduced by
Consider using the path module for constructing paths since they are otherwise not cross-OS compatible.
Loading history...
52
    this._checkFile(false, 'destination', 'Destination folder not found')
53
    this.additionalHelpers = options.additionalHelpers || {}
54
    this.filename          = options.outFile
55
    this.moduleName        = options.moduleName
56
    this.className         = options.className
57
    this.modelPath         = options.modelPath
58
    this.docsPath          = options.docsPath
59
60
    this._checkFile()
61
    this._content = fs.readFileSync(this.filename).toString()
62
63
    this.data = this._parseData()
64
65
    this._checkFile(false, 'templatePath', 'Template path does not exists')
66
67
    let parser                  = new SwaggerParser(this.version, this.data, this.parserOptions || {
68
      className     : this.className,
69
      moduleName    : this.moduleName,
70
      packageName   : options.packageName,
71
      packageVersion: options.packageVersion,
72
      modelPath     : this.modelPath,
73
      docsPath      : this.docsPath
74
    })
75
    this.swaggerData            = parser.parse()
76
    this.swaggerData.moduleName = this.moduleName
77
    this.swaggerData.className  = this.className
78
79
    if (!_.size(this.data)) {
80
      throw new Error('Swagger data is empty')
81
    }
82
  }
83
84
  /**
85
   * @const {String} HTML
86
   *
87
   * @return {string}
88
   */
89
  static get HTML () {
90
    return HTML
91
  }
92
93
  /**
94
   * @const {String} Markdown
95
   *
96
   * @return {string}
97
   */
98
  static get Markdown () {
99
    return Markdown
100
  }
101
102
  /**
103
   * Generate documentation
104
   */
105
  generate () {
106
    if (typeof this.generatorCallback === 'function') {
107
      return this.generatorCallback.apply(this, [this.data])
108
    }
109
110
    this._prepareHandlebars()
111
112
    this._generateMain()
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
113
  }
114
115
  _generateMain () {
116
    let template = fs.readFileSync(this.templatePath + 'md.hbs').toString(),
117
        content  = Handlebars.compile(template)(this.swaggerData)
118
119
    this._writeContent(content, this._getMainFileName())
120
121
    this._generateMethods()
122
    this._generateModels()
123
  }
124
125
  _getMainFileName () {
126
    return this.type === DocGenerator.HTML ? 'index.html' : 'README.MD'
127
  }
128
129
  _writeContent (content, fileName) {
130
    fs.writeFileSync((this.destination + '/' + fileName).replace(/\/\//g, '/'), content)
131
  }
132
133
  _generateModels () {
134
135
  }
136
137
  _generateMethods () {
138
139
  }
140
141
  _prepareHandlebars () {
142
    this._registerPartial('methodList')
143
    this._registerPartial('securityDefinitions')
144
145
    let _self = this
146
147
    _.each(this.additionalLayouts, (file, name) => {
148
      _self._registerPartial(file, name)
149
    })
150
151
    this._registerHelpers()
152
  }
153
154
  _registerPartial (filename, templateName) {
155
    templateName = templateName || filename
156
    if (_.isNumber(templateName)) {
157
      templateName = filename.split('/')
158
159
      let clearTemplate = ''
160
161
      for (let i = 0; i < templateName.length; i++) {
162
        if ((clearTemplate = _.trim(templateName[i])).length) {
163
          templateName = clearTemplate
164
        }
165
      }
166
    }
167
    let fileContent = fs.readFileSync(this.templatePath + filename + '.hbs').toString()
168
169
    Handlebars.registerPartial(templateName, fileContent)
170
  }
171
172
  _registerHelpers () {
173
174
    Handlebars.registerHelper('ifCond', function (v1, v2, options) {
175
      if (v1 === v2) {
176
        return options.fn(this)
177
      }
178
      return options.inverse(this)
179
    })
180
181
    Handlebars.registerHelper('ifHas', function (object, paramName, value, options) {
182
      for (let i in object) {
183
        if (!object.hasOwnProperty(i)) {
184
          continue
185
        }
186
187
        let has = object[i][paramName] === value
188
189
        if (has) {
190
          return options.fn(this)
191
        }
192
      }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
193
    })
194
195
    Handlebars.registerHelper('ifDefine', function (object, paramName, options) {
196
      if (typeof object[paramName] !== 'undefined') {
197
        return options.fn(this)
198
      }
199
200
      return options.inverse(this)
201
    })
202
203
    Handlebars.registerHelper('ifLength', function (object, options) {
204
      if (typeof object === 'undefined') {
205
        return options.inverse(this)
206
      }
207
      return object.length ? options.fn(this) : options.inverse(this)
208
    })
209
210
    _.each(this.additionalHelpers, (cb, name) => {
211
      if (typeof cb === 'function') {
212
        cb(name, Handlebars)
213
      }
214
    })
215
  }
216
}
217
218
/**
219
 * @ignore module
220
 * @ignore module.exports
221
 */
222
module.exports = DocGenerator